/*************************************************************************
	> File Name: interrupt.c
	> Author: life
	> Created Time: 2021年07月17日 星期日 14时32分23秒
 ************************************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>

#include <linux/platform_device.h>


#define IRQ_NAME     "maz-interrput"  /* 加载模式后，执行”cat /proc/devices”命令看到的设备名称 */

static int irq_flag = 0;

struct rpi_int_dev{
	int irq_num;
	int gpio;			/* led所使用的GPIO编号		*/
	int irq_type;
	struct gpio_desc * gpiod;
};

struct rpi_int_dev rpi_ints;

static const struct of_device_id rpi_interrupt[] = {
    {
        .compatible = "maz, interrupt",
    },
    {},
};

static irqreturn_t rpi_irq(int irq, void *dev)
{
	static int cnt= 0;
	printk("[%s][%d] cnt %d \n",__func__,__LINE__,cnt++);
    return IRQ_HANDLED;
}


static int interrupt_probe (struct platform_device * pdev)
{

	int err;
#if 0
	enum of_gpio_flags flag;
	flag = 0x1;
//另一种获取GPIO的方法
	rpi_ints.gpio = of_get_gpio_flags(pdev->dev.of_node,0,&flag);
	printk("rpi_ints.gpio is %d\n",rpi_ints.gpio);
#endif
	of_property_read_u32_index(pdev->dev.of_node, "interrupts-gpios", 2, &rpi_ints.irq_type);
		printk(KERN_INFO"irq_type:%d\n",rpi_ints.irq_type);
	rpi_ints.gpio = of_get_named_gpio(pdev->dev.of_node,"interrupts-gpios",0);
	if(rpi_ints.gpio < 0) {
			printk("can't get interrupts-gpios");
			return -EINVAL;
	}
	printk("rpi_ints.gpio is %d\n",rpi_ints.gpio);

	rpi_ints.gpiod =  gpio_to_desc(rpi_ints.gpio);
	rpi_ints.irq_num = gpiod_to_irq(rpi_ints.gpiod);
	printk("irq_num : %d",rpi_ints.irq_num);

	disable_irq(rpi_ints.irq_num);//因为pinctrl的原因要先disable下
	enable_irq(rpi_ints.irq_num);

	err = request_irq(rpi_ints.irq_num,rpi_irq,rpi_ints.irq_type,IRQ_NAME,NULL);
	if(err)
	{
		printk(KERN_INFO"request_irq  err:%d\n",err);
		return -EINVAL;
	}
	else 
	{
		printk(KERN_INFO"request_irq  successfull\n");
		irq_flag = 1;
	}

	printk(KERN_INFO"raspberry interrput init ok\n");
	return  0;
}
static int interrupt_remove (struct platform_device * pdev)
{

	if(irq_flag)
		free_irq(rpi_ints.irq_num,NULL);
	printk(KERN_INFO"interrputs_exit exit\n");
	return	0;

}

static struct platform_driver rpi_int_drv={
	.probe  = interrupt_probe,
	.remove = interrupt_remove,
	.driver = {
		.name   = "maz, interrupt",
		.owner = THIS_MODULE,
		.of_match_table = rpi_interrupt
	},
};

static int __init interrupt_init(void)
{
	platform_driver_register(&rpi_int_drv);
	return 0;
}

static void __exit interrupt_exit(void)
{
	platform_driver_unregister(&rpi_int_drv);
}
module_init(interrupt_init);
module_exit(interrupt_exit);

/* 描述驱动程序的一些信息，不是必须的 */
MODULE_AUTHOR("ChenBlue");
MODULE_VERSION("0.1.0");
MODULE_DESCRIPTION("raspberry interrupts Driver");
MODULE_LICENSE("GPL");


